﻿using System;
using System.ComponentModel.Design;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Runtime.InteropServices;
using EnvDTE;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.VersionControl.Client;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.TeamFoundation;
using Microsoft.VisualStudio.TeamFoundation.VersionControl;
using TfsBranchLib2.View;
using TfsComLib.FolderDiff;

namespace MBas13.BranchedHistory2
{
    /// <summary>
    ///     This is the class that implements the package exposed by this assembly.
    ///     The minimum requirement for a class to be considered a valid package for Visual Studio
    ///     is to implement the IVsPackage interface and register itself with the shell.
    ///     This package uses the helper classes defined inside the Managed Package Framework (MPF)
    ///     to do it: it derives from the Package class that provides the implementation of the
    ///     IVsPackage interface and uses the registration attributes defined in the framework to
    ///     register itself and its components with the shell.
    /// </summary>
    // This attribute tells the PkgDef creation utility (CreatePkgDef.exe) that this class is
    // a package.
    [PackageRegistration(UseManagedResourcesOnly = true)]
    // This attribute is used to register the information needed to show this package
    // in the Help/About dialog of Visual Studio.
    [InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)]
    // This attribute is needed to let the shell know that this package exposes some menus.
    [ProvideMenuResource("Menus.ctmenu", 1)]
    // This attribute registers a tool window exposed by this package.
    [ProvideToolWindow(typeof (BranchedHistoryWindow))]
    [Guid(GuidList.guidBranchedHistory2PkgString)]
    public sealed class BranchedHistory2Package : Package
    {
        public static BranchedHistory2Package Current;

        /// <summary>
        ///     Default constructor of the package.
        ///     Inside this method you can place any initialization code that does not require
        ///     any Visual Studio service because at this point the package object is created but
        ///     not sited yet inside Visual Studio environment. The place to do all the other
        ///     initialization is the Initialize method.
        /// </summary>
        public BranchedHistory2Package()
        {
            Current = this;
            Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "Entering constructor for: {0}", ToString()));
        }

        /// <summary>
        ///     This function is called when the user clicks the menu item that shows the
        ///     tool window. See the Initialize method to see how the menu item is associated to
        ///     this function using the OleMenuCommandService service and the MenuCommand class.
        /// </summary>
        private void ShowToolWindow(object sender, EventArgs e)
        {
            // Get the instance number 0 of this tool window. This window is single instance so this instance
            // is actually the only one.
            // The last flag is set to true so that if the tool window does not exists it will be created.
            var window = FindToolWindow(typeof (BranchedHistoryWindow), 0, true);
            if ((null == window) || (null == window.Frame))
            {
                throw new NotSupportedException(Resources.CanNotCreateWindow);
            }
            var windowFrame = (IVsWindowFrame) window.Frame;
            ErrorHandler.ThrowOnFailure(windowFrame.Show());
        }


        /////////////////////////////////////////////////////////////////////////////
        // Overridden Package Implementation

        #region Package Members

        /// <summary>
        ///     Initialization of the package; this method is called right after the package is sited, so this is the place
        ///     where you can put all the initialization code that rely on services provided by VisualStudio.
        /// </summary>
        protected override void Initialize()
        {
            Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "Entering Initialize() of: {0}", ToString()));
            base.Initialize();

            // Add our command handlers for menu (commands must exist in the .vsct file)
            var mcs = GetService(typeof (IMenuCommandService)) as OleMenuCommandService;
            if (null != mcs)
            {
                // Create the command for the menu item.
                var menuCommandID = new CommandID(GuidList.guidBranchedHistory2CmdSet,
                    (int) PkgCmdIDList.cmdidBranchedHistory);
                var menuItem = new MenuCommand(ShowBranchedHistoryWindow, menuCommandID);
                mcs.AddCommand(menuItem);
                // Create the command for the tool window
                //CommandID toolwndCommandID = new CommandID(GuidList.guidBranchedHistory2CmdSet, (int)PkgCmdIDList.cmdidBranchedHistory);
                //MenuCommand menuToolWin = new MenuCommand(ShowToolWindow, toolwndCommandID);
                //mcs.AddCommand( menuToolWin );
            }
        }

        #endregion

        /// <summary>
        ///     This function is the callback used to execute a command when the a menu item is clicked.
        ///     See the Initialize method to see how the menu item is associated to this function using
        ///     the OleMenuCommandService service and the MenuCommand class.
        /// </summary>
        private void MenuItemCallback(object sender, EventArgs e)
        {
            // Show a Message Box to prove we were here
            var uiShell = (IVsUIShell) GetService(typeof (SVsUIShell));
            var clsid = Guid.Empty;
            int result;
            ErrorHandler.ThrowOnFailure(uiShell.ShowMessageBox(
                0,
                ref clsid,
                "BranchedHistory2",
                string.Format(CultureInfo.CurrentCulture, "Inside {0}.MenuItemCallback()", ToString()),
                string.Empty,
                0,
                OLEMSGBUTTON.OLEMSGBUTTON_OK,
                OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST,
                OLEMSGICON.OLEMSGICON_INFO,
                0, // false
                out result));
        }

        /// <summary>
        ///     This function is called when the user clicks the menu item that shows the
        ///     tool window. See the Initialize method to see how the menu item is associated to
        ///     this function using the OleMenuCommandService service and the MenuCommand class.
        /// </summary>
        private void ShowBranchedHistoryWindow(object sender, EventArgs e)
        {
            try
            {
                // Get the instance number 0 of this tool window. This window is single instance so this instance
                // is actually the only one.
                // The last flag is set to true so that if the tool window does not exists it will be created.
                var window = FindToolWindow(typeof (BranchedHistoryWindow), 0, true);
                if ((null == window) || (null == window.Frame))
                {
                    throw new NotSupportedException(Resources.CanNotCreateWindow);
                }
                var control = window.Content as BranchedHistoryControl;
                if (control != null)
                {
                    control.UpdateContextData(GetCurrentSourceControlServerPath(), GetVersionControlServer());
                }
                var windowFrame = (IVsWindowFrame) window.Frame;
                ErrorHandler.ThrowOnFailure(windowFrame.Show());
            }
            catch (Exception ex)
            {
                ShowMessage(ex.ToString());
            }
        }


        public string GetCurrentSourceControlServerPath()
        {
            try
            {
                var dte = GetGlobalService(typeof (DTE)) as DTE;
                var extObject = dte.GetObject("Microsoft.VisualStudio.TeamFoundation.TeamFoundationServerExt");
                var ext = extObject as TeamFoundationServerExt;
                var vce =
                    (VersionControlExt)
                        dte.GetObject("Microsoft.VisualStudio.TeamFoundation.VersionControl.VersionControlExt");
                var pendingChangesExt = vce.PendingChanges;
                var ws = pendingChangesExt.Workspace;
                var selectedItems = vce.Explorer.SelectedItems;
                var item = selectedItems.FirstOrDefault();
                if (item != null)
                {
                    return item.SourceServerPath;
                }
                return null;
            }
            catch (Exception ex)
            {
                throw new Exception("Error Get current source control server path", ex);
            }
        }

        internal void ShowChangesetDetails(int changesetId)
        {
            try
            {
                var dte = GetGlobalService(typeof (DTE)) as DTE;
                if (dte == null) throw new Exception("Can't get global service DTE");
                var extObject = dte.GetObject("Microsoft.VisualStudio.TeamFoundation.TeamFoundationServerExt");
                var ext = extObject as TeamFoundationServerExt;
                var vce =
                    (VersionControlExt)
                        dte.GetObject("Microsoft.VisualStudio.TeamFoundation.VersionControl.VersionControlExt");
                vce.ViewChangesetDetails(changesetId);
            }
            catch (Exception ex)
            {
                ShowMessage(ex.Message);
            }
        }

        internal void ShowCompare(VersionControlServer versionControlServer, bool isFile, string path1, int version1,
            string path2, int version2)
        {
            try
            {
                var dte = GetGlobalService(typeof (DTE)) as DTE;
                if (dte == null) throw new Exception("Can't get global service DTE");
                var extObject = dte.GetObject("Microsoft.VisualStudio.TeamFoundation.TeamFoundationServerExt");
                var ext = extObject as TeamFoundationServerExt;
                var vce =
                    (VersionControlExt)
                        dte.GetObject("Microsoft.VisualStudio.TeamFoundation.VersionControl.VersionControlExt");

                if (isFile)
                {
                    var item1 = new DiffItemVersionedFile(versionControlServer, path1,
                        VersionSpec.ParseSingleSpec("C" + version1, null));
                    var item2 = new DiffItemVersionedFile(versionControlServer, path2,
                        VersionSpec.ParseSingleSpec("C" + version2, null));
                    Difference.VisualDiffItems(versionControlServer, item1, item2);
                }
                else
                {
                    using (var folderDiffDialog = new DialogFolderDiffInv(
                        versionControlServer,
                        new ItemIdentifier(path1,
                            VersionSpec.ParseSingleSpec("C" + version1, null)),
                        version1,
                        new ItemIdentifier(path2,
                            VersionSpec.ParseSingleSpec("C" + version2, null)),
                        version2))
                    {
                        folderDiffDialog.ShowDialog();
                    }
                }
            }
            catch (Exception ex)
            {
                ShowMessage(ex.Message);
            }
        }


        internal VersionControlServer GetVersionControlServer()
        {
            try
            {
                var dte = GetGlobalService(typeof (DTE)) as DTE;
                if (dte == null) throw new Exception("Can't get global service DTE");
                var extObject = dte.GetObject("Microsoft.VisualStudio.TeamFoundation.TeamFoundationServerExt");
                var ext = extObject as TeamFoundationServerExt;
                if (ext == null)
                {
                    return null;
                }
                var vce =
                    (VersionControlExt)
                        dte.GetObject("Microsoft.VisualStudio.TeamFoundation.VersionControl.VersionControlExt");
                VersionControlServer versionControlServer;
                if ((vce != null) && (vce.Explorer != null) && (vce.Explorer.Workspace != null))
                {
                    versionControlServer = vce.Explorer.Workspace.VersionControlServer;
                }
                else
                {
                    using (
                        var collection = new TfsTeamProjectCollection(new Uri(ext.ActiveProjectContext.DomainUri),
                            new TfsClientCredentials() /*new UICredentialsProvider()*/))
                    {
                        versionControlServer = collection.GetService<VersionControlServer>();
                    }
                }
                return versionControlServer;
            }
            catch (Exception ex)
            {
                throw new Exception("Get version control server failure", ex);
            }
        }

        private void ShowMessage(string message)
        {
            var uiShell = (IVsUIShell) GetService(typeof (SVsUIShell));
            var clsid = Guid.Empty;
            int result;
            ErrorHandler.ThrowOnFailure(uiShell.ShowMessageBox(
                0,
                ref clsid,
                "BranchedHistory2Package",
                message,
                string.Empty,
                0,
                OLEMSGBUTTON.OLEMSGBUTTON_OK,
                OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST,
                OLEMSGICON.OLEMSGICON_INFO,
                0, // false
                out result));
        }
    }
}